# core/base_page.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from utils.log_utils import log
from utils.config_util import ConfigUtil
from selenium.webdriver.support.ui import Select
from utils.screenshot_utils import save_screenshot  # 假设已实现截图工具
from selenium.common.exceptions import StaleElementReferenceException


class BasePage:
    def __init__(self, driver=None):
        # 初始化浏览器驱动（增强版）
        if driver is None:
            browser = ConfigUtil.get_browser()
            if browser == "chrome":
                self.driver = webdriver.Chrome()
            elif browser == "firefox":
                self.driver = webdriver.Firefox()
            elif browser == "edge":
                self.driver = webdriver.Edge()
            else:
                raise ValueError(f"不支持的浏览器：{browser}")
            self.driver.maximize_window()
            self.driver.implicitly_wait(10)
        else:
            self.driver = driver

    def open_url(self, url):
        """打开页面并等待加载完成"""
        self.driver.get(url)
        self.wait_for_page_load()
        return self

    def wait_for_page_load(self, timeout=10):
        """等待页面加载完成（通过检查 document.readyState）"""
        try:
            WebDriverWait(self.driver, timeout).until(
                lambda d: d.execute_script("return document.readyState") == "complete"
            )
            log.info("页面加载完成")
        except TimeoutException:
            log.warning("页面加载超时")

    def find_element(self, locator, timeout=10):
        """显式等待元素可见"""
        try:
            element = WebDriverWait(self.driver, timeout).until(
                EC.visibility_of_element_located(locator)
            )
            log.info(f"找到元素：{locator}")
            return element
        except TimeoutException:
            log.error(f"超时未找到元素：{locator}")
            save_screenshot(self.driver, f"error_{locator[1]}")  # 截图留存
            raise

    def find_elements(self, locator, timeout=10):
        """显式等待多个元素可见"""
        try:
            elements = WebDriverWait(self.driver, timeout).until(
                EC.visibility_of_all_elements_located(locator)
            )
            log.info(f"找到 {len(elements)} 个元素：{locator}")
            return elements
        except TimeoutException:
            log.error(f"超时未找到元素：{locator}")
            raise

    def click(self, locator, timeout=10):
        """点击元素（包含等待）"""
        self.find_element(locator, timeout).click()
        log.info(f"点击元素：{locator}")
        return self

    def send_keys(self, locator, text, timeout=10):
        """输入文本（包含等待和清空）"""
        element = self.find_element(locator, timeout)
        element.clear()
        element.send_keys(text)
        log.info(f"向元素 {locator} 输入：{text}")
        return self

    def get_text(self, locator, timeout=10):
        """获取元素文本"""
        text = self.find_element(locator, timeout).text
        log.info(f"元素 {locator} 的文本为：{text}")
        return text

    def execute_script(self, script, *args):
        """执行 JavaScript 脚本"""
        result = self.driver.execute_script(script, *args)
        log.info(f"执行 JS 脚本：{script}")
        return result

    def is_element_present(self, locator, timeout=3):
        """检查元素是否存在（短超时）"""
        try:
            self.find_element(locator, timeout)
            return True
        except (TimeoutException, NoSuchElementException):
            return False

    def wait_for_element_disappear(self, locator, timeout=10):
        """等待元素消失"""
        try:
            WebDriverWait(self.driver, timeout).until(
                EC.invisibility_of_element_located(locator)
            )
            log.info(f"元素 {locator} 已消失")
            return True
        except TimeoutException:
            log.error(f"元素 {locator} 未消失")
            return False

    def switch_to_iframe(self, locator, timeout=10):
        """切换到 iframe"""
        iframe = self.find_element(locator, timeout)
        self.driver.switch_to.frame(iframe)
        log.info(f"切换到 iframe：{locator}")
        return self

    def switch_to_default_content(self):
        """切回默认页面"""
        self.driver.switch_to.default_content()
        log.info("切回默认页面")
        return self

    def get_title(self):
        """获取页面标题"""
        return self.driver.title

    def get_url(self):
        """获取当前 URL"""
        return self.driver.current_url

    def select_by_visible_text(self, locator, text, timeout=10):
        """通过可见文本选择下拉框选项"""
        try:
            element = self.find_element(locator, timeout)
            select = Select(element)
            select.select_by_visible_text(text)
            log.info(f"在下拉框 {locator} 中选择文本为 '{text}' 的选项")
            return self
        except StaleElementReferenceException:
            # 处理元素过时异常，重新查找元素并选择
            log.warning(f"元素过时，重新查找并选择下拉框选项: {locator}, {text}")
            element = self.find_element(locator, timeout)
            select = Select(element)
            select.select_by_visible_text(text)
            return self

    def select_by_value(self, locator, value, timeout=10):
        """通过 value 属性选择下拉框选项"""
        try:
            element = self.find_element(locator, timeout)
            select = Select(element)
            select.select_by_value(value)
            log.info(f"在下拉框 {locator} 中选择 value 为 '{value}' 的选项")
            return self
        except StaleElementReferenceException:
            # 处理元素过时异常，重新查找元素并选择
            log.warning(f"元素过时，重新查找并选择下拉框选项: {locator}, {value}")
            element = self.find_element(locator, timeout)
            select = Select(element)
            select.select_by_value(value)
            return self

    def select_by_index(self, locator, index, timeout=10):
        """通过索引选择下拉框选项"""
        try:
            element = self.find_element(locator, timeout)
            select = Select(element)
            select.select_by_index(index)
            log.info(f"在下拉框 {locator} 中选择索引为 {index} 的选项")
            return self
        except StaleElementReferenceException:
            # 处理元素过时异常，重新查找元素并选择
            log.warning(f"元素过时，重新查找并选择下拉框选项: {locator}, {index}")
            element = self.find_element(locator, timeout)
            select = Select(element)
            select.select_by_index(index)
            return self

    def quit(self):
        """关闭浏览器"""
        if self.driver:
            self.driver.quit()
            log.info("浏览器已关闭")
